package com.example.log_db.aspect;

import com.example.log_db.annotation.LogRecord;
import com.example.log_db.config.LogConfig;
import com.example.log_db.model.LogInfo;
import com.example.log_db.service.LogService;
import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.servlet.http.HttpServletRequest;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import java.lang.reflect.Method;
import java.time.LocalDateTime;
import java.util.Arrays;
import java.util.Objects;

/**
 * 日志记录切面
 */
@Slf4j
@Aspect
@Component
@RequiredArgsConstructor
public class LogRecordAspect {

    private final LogService logService;
    private final LogConfig logConfig;
    private final ObjectMapper objectMapper;

    /**
     * 定义切点 - 所有使用@LogRecord注解的方法
     */
    @Pointcut("@annotation(com.example.log_db.annotation.LogRecord)")
    public void logPointcut() {
    }

    /**
     * 环绕通知
     */
    @Around("logPointcut()")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        // 如果日志记录功能未启用，直接执行原方法并返回结果
        if (!logConfig.isEnabled()) {
            return joinPoint.proceed();
        }

        // 开始时间
        long startTime = System.currentTimeMillis();
        // 返回结果
        Object result = null;
        // 异常信息
        String exceptionMessage = null;

        try {
            // 执行目标方法
            result = joinPoint.proceed();
            return result;
        } catch (Throwable e) {
            // 记录异常信息
            exceptionMessage = e.getMessage();
            throw e;
        } finally {
            // 结束时间
            long endTime = System.currentTimeMillis();
            // 异步记录日志
            recordLog(joinPoint, result, endTime - startTime, exceptionMessage);
        }
    }

    /**
     * 异步记录日志
     */
    @Async("logExecutor")
    public void recordLog(ProceedingJoinPoint joinPoint, Object result, long executionTime, String exceptionMessage) {
        try {
            // 获取请求信息
            ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
            HttpServletRequest request = attributes != null ? attributes.getRequest() : null;

            // 获取方法签名
            MethodSignature signature = (MethodSignature) joinPoint.getSignature();
            Method method = signature.getMethod();

            // 获取注解信息
            LogRecord logRecord = method.getAnnotation(LogRecord.class);
            if (logRecord == null) {
                return;
            }

            // 构建日志信息
            LogInfo.LogInfoBuilder logInfoBuilder = LogInfo.builder()
                    .operationType(logRecord.operationType())
                    .description(logRecord.description())
                    .method(method.getDeclaringClass().getName() + "." + method.getName())
                    .executionTime(executionTime)
                    .operateTime(LocalDateTime.now());

            // 设置请求信息
            if (request != null) {
                logInfoBuilder
                        .requestUrl(request.getRequestURI())
                        .ip(getIpAddress(request))
                        .userId(getUserId(request));
            }

            // 记录请求参数
            if (logRecord.recordParams()) {
                try {
                    String params = objectMapper.writeValueAsString(joinPoint.getArgs());
                    logInfoBuilder.requestParams(params);
                } catch (Exception e) {
                    logInfoBuilder.requestParams(Arrays.toString(joinPoint.getArgs()));
                }
            }

            // 记录返回结果
            if (logRecord.recordResult() && result != null) {
                try {
                    String resultJson = objectMapper.writeValueAsString(result);
                    logInfoBuilder.responseResult(resultJson);
                } catch (Exception e) {
                    logInfoBuilder.responseResult(result.toString());
                }
            }

            // 记录异常信息
            if (exceptionMessage != null) {
                logInfoBuilder.exceptionMessage(exceptionMessage);
            }

            // 保存日志
            logService.saveLog(logInfoBuilder.build());
        } catch (Exception e) {
            log.error("记录操作日志异常", e);
        }
    }

    /**
     * 获取请求IP地址
     */
    private String getIpAddress(HttpServletRequest request) {
        String ip = request.getHeader("X-Forwarded-For");
        if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("Proxy-Client-IP");
        }
        if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("WL-Proxy-Client-IP");
        }
        if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("HTTP_CLIENT_IP");
        }
        if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("HTTP_X_FORWARDED_FOR");
        }
        if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddr();
        }
        return ip;
    }

    /**
     * 获取用户ID
     * 实际项目中可以从请求头、Session或Token中获取
     */
    private String getUserId(HttpServletRequest request) {
        // 这里只是一个示例，实际项目中应该根据认证方式获取用户ID
        return "anonymous";
    }
}